package pl.edu.pw.stud.ltrzaska.classloader;

import org.apache.log4j.Logger;

import pl.edu.pw.stud.ltrzaska.exception.ClassloaderException;

/**
 * Klasa-fasada. Udostepnia usluge dynamicznego zaladowania klasy (runtime) po
 * uprzednim zaladowaniu jej ze zrodla np. dysku.
 * 
 */
public class DynamicClassLoader {
	private static final transient Logger LOGGER = Logger.getLogger(DynamicClassLoader.class);
	private ClassCache<Object> cache;
	private String sourcePath;

	/**
	 * Konstruktor pobierajacy sciezke do katalogu z plikami klas do
	 * zaladowania.
	 * 
	 * @param sourcePath
	 */
	public DynamicClassLoader(String sourcePath) {
		this.cache = ClassCache.getInstance();
		this.sourcePath = sourcePath;
	}

	/**
	 * Dynamicznie laduje klase <code>Class<?></code> po uprzednim zaladowaniu
	 * ze zrodla.
	 * 
	 * @param shortClassName
	 *            nazwa klasy (asocjacyjna), po ktorej wyszukujemy w LDAP.
	 * @throws PoltaxIntegrationException
	 */
	public Class<?> load(String shortClassName) throws ClassloaderException {
		Class<?> ret = null;
		BinaryClassLoader bcl = BinaryClassLoader.create();
		ClassContainer cc = null;
		if (!this.cache.containsKey(shortClassName)) {
			LOGGER.debug("Retrieving class bytecode from source.");
			retrieveFromSource(shortClassName);
		} else {
			LOGGER.debug("Retrieving class from Cache.");
		}
		cc = (ClassContainer) this.cache.get(shortClassName);
		try {
			ret = bcl.loadClass(cc.getFullyQualifiedName(), cc.getByteCode());
		} catch (ClassloaderException e) {
			this.cache.remove(shortClassName);
			throw e;
		}
		return ret;
	}

	private void retrieveFromSource(String className) throws ClassloaderException {
		ClassContainer cc;
		BinaryClassLoader bcl = BinaryClassLoader.create();
		// TODO here open file and load  
		cc = new ClassContainer(bcl.loadFileToClassBytes(className), className);
		this.cache.put(className, cc);
	}
}
